package claim.fuzzy;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import claim.geom.Feature;
import claim.geom.PointFeature;
import claim.layer.Layer;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;

public class CFCM {

	private static final Log LOG = LogFactory.getLog(Class.class.getName());
	
	private Layer layer0;
	private Layer layer1;

	private Geometry boundingBox;

	private List<Feature> cfcmPoints;

	private double[] cfcmValues;

	public CFCM(Layer layer0, Layer layer1) {
		this.layer0 = layer0;
		this.layer1 = layer1;
		this.boundingBox = computeBBox();
	}
	
	private Geometry computeBBox() {
		return (layer0.getBoundingBox().intersection(layer1.getBoundingBox())).getEnvelope();
	}

	public List<Feature> getCFCMPoints() {
		return cfcmPoints;
	}
	
	public double getValue(String objClass, double x, double y) {
		try {
			double membership0 = layer0.getMembership(objClass, x, y);
			double membership1 = layer1.getMembership(objClass, x, y);
			if (membership0 == -1 || membership1 == -1 || (membership0 == 0 && membership1 == 0)) {
				return -1;
			} else {
				return 1- Math.abs(membership0-membership1);
			}
		} catch (Exception e) {
			LOG.error("could not get value at " + x + ", " + y);
			return -1;
		}
		
	}
	
	public void computeCFCMPoints(String objClass, int numX, int numY) {
		LOG.info("computing cfcm for object class '" +objClass+ "'");
		double bBoxWidth = boundingBox.getEnvelope().getCoordinates()[1].x - boundingBox.getEnvelope().getCoordinates()[0].x;
		double bBoxHeight = boundingBox.getEnvelope().getCoordinates()[2].y - boundingBox.getEnvelope().getCoordinates()[1].y;
		double deltaX = bBoxWidth / (numX-1);
		double deltaY = bBoxHeight / (numY-1);
		double x0 = boundingBox.getEnvelope().getCoordinates()[0].x;
		double y0 = boundingBox.getEnvelope().getCoordinates()[1].y;
		Point[][] points = new Point[numX][numY];
		List<Double> cfcm = new ArrayList<Double>(numX*numY);
		double x, y;
		this.cfcmPoints = new ArrayList<Feature>();
		double cfcmValue;
		for (int j = 0; j < numY; j++) {
			LOG.info("row " + j + " of " + numY);
			for (int i = 0; i < numX; i++) {
				x = x0 + i*deltaX;
				y = y0 + j*deltaY;
				Coordinate coordinate = new Coordinate(x, y);
				points[i][j] = new GeometryFactory().createPoint(coordinate);
				cfcmValue = getValue(objClass, x, y);
				if (cfcmValue != -1) {
					cfcm.add(cfcmValue);
				}
				double member0 = layer0.getMembership(objClass, x, y);
				double member1 = layer1.getMembership(objClass, x, y);
				cfcmPoints.add(new PointFeature(points[i][j], member0, member1, cfcmValue));
//				LOG.debug("cfcm = " + cfcmValue + " at (" +x+ "/" +y+ ")");
			}
		}
		this.cfcmValues = fillArray(cfcm);
	}

	private double[] fillArray(List<Double> cfcm) {
		double[] array = new double[cfcm.size()];
		for (int i = 0; i < cfcm.size(); i++) {
			array[i] = cfcm.get(i);
		}
		return array;
	}

	public double[] getValues() {
		return cfcmValues;
	}
	
}
